This is a stripped-down and partially rewritten subset of dietlibc,
capable just enough to build sninit but probably not for anything else.
See doc/libc.txt for explanation.

Check http://www.fefe.de/dietlibc/ for the original source.

File structure:

	include         generic headers
	*.c             generic libc routines (string and time)
	ARCH/           platform-specific syscall code
	ARCH/bits/      platform-specific constants
	libtest/        libc routines only used by test/ code

There are no proper Makefiles anywhere under libc/.
To build it, run "make libc" from the top source directory.


Syscall code
~~~~~~~~~~~~
For most platforms, syscall argument placement differs from that
of regular functions. On all platforms, syscall number must be passed
alongside the arguments.

The bundled libc (and dietlibc, and pretty much anything else except musl)
declares syscalls as regular functions, and moves arguments into their proper
locations in assembly code. Check platform README files for more info.

All syscalls return -ECODE on failure. It's libc duty to move that to global
errno and return -1 from the function. That's wrong, but it's in the standard.

Errno handling and common argument code is in _syscall.s.
The calls themselves are typically trivial (load NR_*, invoke _syscall),
so most are routinely generated by _syscall.sh. See platform Makefiles.
There are some special hand-written syscalls on most platforms however.


Startup code
~~~~~~~~~~~~
The entry point is in _start.s for all platforms.
_exit is there as well, because it must be called to end the process.

What entry code does is setting up the topmost frame and calling
_exit(main(argc, argv, envp)). Where argc, argv, envp are when _start
is invoked is highly platform-dependent.
The most common answer is "not where main() expects them to be".


Syscall constants
~~~~~~~~~~~~~~~~~
C headers do not play well with assembly sources. Syscall numbers are provided
in C headers by the kernel. Within bundled libc, this is resolved by grepping
the headers for raw numbers and defining them via .equ's in assembly.
See per-platform _syscall.sh on how this is done.

This of course means the numbers must be kept is sync with the actual kernel
data somehow. The good news is that syscall numbers are among the most stable
parts of the linux kernel.

Quick check if you have a usable toolchain with some kind of libc:

    echo "__NR_ppoll" | ARCH-gcc -E -include syscall.h - | grep . | grep -v '^#'

Keep it mind the output may look like "(0 +336)" on some platforms.


Porting the bundled libc
~~~~~~~~~~~~~~~~~~~~~~~~
To add a new architecture, add a directory with proper bits/ headers, _start.s
and per-syscall .s files. Then set ARCH=your-new-arch and build.

For bits/ part, grab relevant constants from the kernel headers.
Beware the kernel headers are a huge mess of #ifdefs.
You need to grab only the values for your particular architecture.

For startup code and syscall argument handling, check some existing libc.
Musl: arch/ARCH/crt_arch.h for startup, arch/ARCH/syscall_arch.h for syscalls.
Dietlibc: ARCH/start.S, and macro defines at the end of ARCH/syscalls.h.

There are some x_* tests in test/ directory, those may help during early
stages. Run them via qemu-ARCH -strace to make sure they do what they are
expected to do.

When porting, do *NOT* use x86 as a template! It is overly complex and highly
unusual in many aspects. Use something saner instead, like arm or x86_64.


Extended syscalls
~~~~~~~~~~~~~~~~~
Several well-known syscalls are special cases of other, less-known syscalls
that typically accept more arguments. Examples:

	(v)fork = clone with certain flags
	wait, waitpid = wait4 with certain arguments
	open = openat(AT_FDCWD, ...), and same goes for all *at syscalls
	sigaction may be a case of rt_sigaction, same for other rt_* calls

Some platforms only provide extended syscalls, so common ones must
be implemented by supplying required arguments for respective extended calls.

Syscalls working with sigset_t have a extra "hidden" sizeof(sigset_t) argument
which must be supplied by the libc code. Man pages do mention it but typically
somewhere at the bottom. Failure to provide the right value results in EINVAL.

reboot() is a 3-argument syscall, but init expects 1-argument version provided
by modern libcs.

Socket syscalls on some platforms have a single entry point, socketcall(2),
so there is no __NR_bind, __NR_accept, __NR_listen etc.
